<html>
  <head>
    <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>70道js面试题理解 | 🦌</title>
<link rel="shortcut icon" href="https://croatiaparanoia.github.io/blog//favicon.ico?v=1614759965596">
<link href="https://cdn.jsdelivr.net/npm/remixicon@2.3.0/fonts/remixicon.css" rel="stylesheet">
<link rel="stylesheet" href="https://croatiaparanoia.github.io/blog//styles/main.css">
<link rel="alternate" type="application/atom+xml" title="70道js面试题理解 | 🦌 - Atom Feed" href="https://croatiaparanoia.github.io/blog//atom.xml">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Droid+Serif:400,700">



    <meta name="description" content="面试题理解
此文章是根据 70 道 Javascript 面试题【译】 的题目， 自己的理解所写出来的。
欢迎大家在下面留下不同想法。
1.undefined 和 null 有什么区别？

undefined 是未指定特定值的变量的默认值，..." />
    <meta name="keywords" content="面试题,Javascript" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0/katex.min.css">
    <script src="https://cdn.bootcss.com/highlight.js/9.12.0/highlight.min.js"></script>
  </head>
  <body>
    <div class="main">
      <div class="main-content">
        <div class="site-header">
  <a href="https://croatiaparanoia.github.io/blog/">
  <img class="avatar" src="https://croatiaparanoia.github.io/blog//images/avatar.png?v=1614759965596" alt="">
  </a>
  <h1 class="site-title">
    🦌
  </h1>
  <p class="site-description">
    万物皆有裂痕，那是光照进来的地方。
  </p>
  <div class="menu-container">
    
      
        <a href="/blog/" class="menu">
          首页
        </a>
      
    
      
        <a href="/blog/archives" class="menu">
          归档
        </a>
      
    
      
        <a href="/blog/tags" class="menu">
          标签
        </a>
      
    
      
        <a href="/blog/post/about" class="menu">
          关于
        </a>
      
    
  </div>
  <div class="social-container">
    
      
        <a href="https://github.com/CroatiaParanoia" target="_blank">
          <i class="ri-github-line"></i>
        </a>
      
    
      
    
      
    
      
    
      
    
  </div>
</div>

        <div class="post-detail">
          <article class="post">
            <h2 class="post-title">
              70道js面试题理解
            </h2>
            <div class="post-info">
              <span>
                2021-01-05
              </span>
              <span>
                28 min read
              </span>
              
                <a href="https://croatiaparanoia.github.io/blog/tag/JcSpldVDn/" class="post-tag">
                  # 面试题
                </a>
              
                <a href="https://croatiaparanoia.github.io/blog/tag/5gGD3PI9U/" class="post-tag">
                  # Javascript
                </a>
              
            </div>
            
              <img class="post-feature-image" src="https://croatiaparanoia.github.io/blog//post-images/70-dao-js-mian-shi-ti-li-jie.jpeg" alt="">
            
            <div class="post-content-wrapper">
              <div class="post-content">
                <h1 id="面试题理解">面试题理解</h1>
<p>此文章是根据 <a href="https://juejin.cn/post/6913534577684414472">70 道 Javascript 面试题【译】</a> 的题目， 自己的理解所写出来的。</p>
<p>欢迎大家在下面留下不同想法。</p>
<h2 id="1undefined-和-null-有什么区别">1.undefined 和 null 有什么区别？</h2>
<blockquote>
<p>undefined 是未指定特定值的变量的默认值，或者没有显式返回值的函数。</p>
</blockquote>
<p>未定义，没有预设过该值， 比如访问一个对象不存在的属性。</p>
<blockquote>
<p>null 是『不代表任何值的值』</p>
</blockquote>
<p>表示该值是有的， 只不过不是正常的返回结果。比如 通过 <code>getElementById</code> 查询一个不存在的元素， 该方法可以肯定有一个返回值， 返回的是匹配结果， 而又因为根据选择器不一定能匹配到元素， 存在为空的情况， 所以， 就应该使用一个  null  去作为一个返回值， 表示有一个结果， 只不过是为空的。</p>
<h2 id="2-运算符">2. &amp;&amp; 运算符</h2>
<p>逻辑与， 属于短路运算符的一种。 当 A &amp;&amp; B ， A 位置结果为真值时， 则会取B位置的结果作为运算结果， 否则取A位置的结果作为运算结果。</p>
<p>注意：</p>
<p>当 <code>fn1() &amp;&amp; fn2()</code> 这样时， 首先是执行 fn1 函数， 得到返回值后， 根据返回值对应的布尔值， 再来决定是否会走到后面的 <code>fn2()</code> ， 如果fn1 函数执行结果为假值， 则不会执行fn2。因为 &amp;&amp; 运算符已经得到了一个结果了。</p>
<h2 id="3-运算符能做什么">3. || 运算符能做什么</h2>
<p>逻辑或，短路运算符的一种。 当有 A || B， A位置的结果为假时， 则会取B位置的结果作为运算结果， 否则取A位置的结果作为运算结果。</p>
<p>此运算符通常除了条件计算， 还有一个应用场景就是 取默认值， 如下</p>
<pre><code class="language-javascript">const defaultValue = { ... };

function fn(inputValue){
  const v = inputValue || defaultValue;
  ...
}

</code></pre>
<p>注意， &amp;&amp; 和 || 两个运算符， 都是将值进行 <code>Boolean</code> 运算后的结果，再去进行与和或的运算的，也就是说， 在上面例子中 ，如果inputValue 传入的是 0， NaN,  null， ''， undefined， false （也就是 21题所说的 <strong>虚值</strong>）， 都会走到 后面的 <code>defaultValue</code> 中</p>
<h3 id="4-使用-或一元加运算符是将字符串转换为数字的最快方法吗">4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗？</h3>
<blockquote>
<p>根据MDN文档，<code>+</code>是将字符串转换为数字的最快方法，因为如果值已经是数字，它不会执行任何操作。</p>
</blockquote>
<p>但是个人认为， 使用隐式转换的方法， 会给代码的可读性带来一定的影响， 如果可以， 尽量使用直观的数据类型转换， 让读者可以很肯定的知道，该语句返回的数据类型是什么。</p>
<p>当然， 如果还是想用 这些符号， 也可以考虑封装基础的转换函数， 如：</p>
<pre><code class="language-javascript">function toNumber(v){
  return +v;
}


+a // =&gt;
toNumber(a);
</code></pre>
<p>既满足了想用 + 操作符的心理， 又有了可读性。</p>
<h2 id="5-dom-是什么">5. DOM 是什么？</h2>
<p>Document Object Model 的简写，表示 <strong>文档对象模型</strong> 。 浏览器在拿到html文件后， 会去解析里面的html标签，并创建出一个树状结构来表现这个html的嵌套， 属性等一些信息。</p>
<p>并同时会交于js 一个 document 的全局对象，通过这个对象， js就可以来操控这个树状结构。（赋予js操控dom 的能力）</p>
<h2 id="6-什么是事件传播">6. 什么是事件传播?</h2>
<p>当一个元素触发某个事件， 首先会从 window 开始， 自顶向下的依次触发，此阶段为捕获阶段， 由外到里。</p>
<p>当到达目标元素时， 则是为 目标阶段。真正触发该元素的该事件。</p>
<p>触发目标元素的事件完毕后， 再从目标元素开始，自底向上的依次触发， 到window为止， 此阶段为冒泡阶段， 由里到外</p>
<blockquote>
<p>事件传播有三个阶段：</p>
<ol>
<li><strong>捕获阶段</strong>–事件从 <code>window</code> 开始，然后向下到每个元素，直到到达目标元素。</li>
<li><strong>目标阶段</strong>–事件已达到目标元素。</li>
<li><strong>冒泡阶段</strong>–事件从目标元素冒泡，然后上升到每个元素，直到到达 <code>window</code>。</li>
</ol>
</blockquote>
<h2 id="7-什么是事件冒泡">7. 什么是事件冒泡？</h2>
<p>当<strong>事件</strong>发生在<strong>DOM</strong>元素上时，事件自底向上的触发， 首先是目标元素触发，再是目标元素的父级元素， 祖父级元素，依次上推，到window触发后为止。</p>
<h3 id="8-什么是事件捕获">8. 什么是事件捕获？</h3>
<p>当<strong>事件</strong>发生在<strong>DOM</strong>元素上时，事件自顶向下的触发， 首先是 window 触发，自顶向下依次触发， 到达目标元素触发后为止。</p>
<h3 id="9-eventpreventdefault-和-eventstoppropagation方法之间有什么区别">9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别？</h3>
<p>event.preventDefault() 阻止事件的默认行为， 比如 a 标签的点击跳转， button[type=submit] 的点击刷新页面等默认行为</p>
<p>event.stopPropagation() 阻止冒泡 或者 捕获阶段， 终止由外到内的捕获， 或者由内到外的冒泡。</p>
<h3 id="10-如何知道是否在元素中使用了eventpreventdefault方法">10. 如何知道是否在元素中使用了<code>event.preventDefault()</code>方法？</h3>
<blockquote>
<p>我们可以在事件对象中使用<code>event.defaultPrevented</code>属性。它返回一个布尔值用来表明是否在特定元素中调用了<code>event.preventDefault()</code>。</p>
</blockquote>
<h3 id="11-为什么此代码-objsomepropx-会引发错误">11. 为什么此代码 <code>obj.someprop.x</code> 会引发错误?</h3>
<pre><code class="language-javascript">const obj = {};

console.log(obj.someprop.x);



// 一层一层的递进，  首先 可以将 obj.someprop.x 分解成  obj.someprop 和 someprop.x

const someprop = obj.someprop; // 此时可以确定 someprop 是undefined。

someprop.x // =&gt; 此时就对应了 undefined.x ， 自然就会报错了。
</code></pre>
<h2 id="12-什么是-eventtarget">12. 什么是 event.target ？</h2>
<p>触发事件的目标元素。 如有结构 div &gt; button， div 绑定点击事件， 点击button， 则会冒泡至div， 触发div的点击事件，但是此时 事件对象中的target 是指的 button 元素， 因为button 是事件触发的目标元素。</p>
<h2 id="13-什么是-eventcurrenttarget">13. 什么是 event.currentTarget？？</h2>
<p>绑定了该事件的元素。如有结构 div &gt; button， div 绑定点击事件， 点击button， 则会冒泡至div， 触发div的点击事件，但是此时 事件对象中的target 是指的 button 元素， 因为button 是事件触发的目标元素。而事件对象中的 currentTarget 就是指向了div， 因为div是绑定了该事件的元素。</p>
<h3 id="14-和-有什么区别">14. == 和 === 有什么区别？</h3>
<p>“==” 首先进行类型的判断， 如果统一， 则直接进行值的判断。（如果是引用类型则比较引用的内存地址）。如果类型不统一， 则首先进行数据类型的转换， 统一了两边数据类型后，再进行比较。</p>
<p>“===” 首先比较类型， 类型不一样就返回false了， 如果类型一样再比较值或者引用地址。不会进行隐式数据类型转换。</p>
<h3 id="15-为什么在-js-中比较两个相似的对象时返回-false">15. 为什么在 JS 中比较两个相似的对象时返回 false？</h3>
<p>先看下面的例子：</p>
<pre><code class="language-javascript">let a = { a: 1 };  
let b = { a: 1 };  
let c = a;  
console.log(a === b); // 打印 false，即使它们有相同的属性  
console.log(a === c); // true  
</code></pre>
<p>js 区分了基本数据类型和复杂数据类型。 而基本数据类型的一大特性就是按值存储， 复杂数据类型则是按引用存储。及， 当进行比较时， 基本数据类型是拿出自己的值， 而复杂数据类型则是拿出自己所在内存中的引用地址， 两者进行比较。</p>
<p>而此例子中， 则是涉及到复杂数据类型的创建， 每创建一个复杂数据类型， js 都会在堆内存中开辟一块空间来对这块的数据进行存储， 并将该内存空间的地址， 作为该语句的返回值（此处就是 字面量形式创建的对象）。</p>
<p>所以 第一行代码的流程是：</p>
<ol>
<li>声明变量a，</li>
<li>通过对象字面量来创建一个新的对象
<ol>
<li>创建这个对象， 首先就在堆内存中开一块空间， 用来表示该对象的存储空间。</li>
<li>将对象中的键值对数据， 置入 该内存空间。</li>
<li>将该内存空间的内存地址， 作为该语句( <code>{a: 1}</code> )的结果， 返回出去 。</li>
</ol>
</li>
<li>此时， 变量a 就接收到了一个内存地址， 该内存地址就是指向了第二步所创建出来的内存空间。</li>
</ol>
<p>然后到第二行， 代码流程同上， 创建了一个完全新的内存空间， 返回了一个完全新的内存地址交给变量b。</p>
<p>第三行， c = a， 此时则是将 a 存储的内存地址， 复制一份， 交给c，此时c 里面存的也是第一行创建的那块内存空间的内存地址。</p>
<p>第四行，<code>console.log(a === b)</code> ， 此时的比较， 则是比较两者的引用地址， 因 两者存放的引用地址并不一致， 所以返回false。</p>
<p>第五行， <code>console.log(a === c)</code> ，此时的比较， 也是比较两者的引用地址， 因为 c 的地址是从a 复制过来的， 所以，c 的地址就是完全等于 a的地址， 故两者一致， 返回true。</p>
<h3 id="16-运算符能做什么">16. !! 运算符能做什么？</h3>
<p>两次取反， 相当于转换为布尔值， 不过个人还是喜欢 Boolean 函数来进行布尔值的转换。</p>
<h3 id="17-如何在一行中计算多个表达式的值">17. 如何在一行中计算多个表达式的值？</h3>
<p>利用圆括号的返回值就是最后一个值的特性， 另外的还有一些写法：</p>
<pre><code class="language-javascript">const arr = ['name', 'nick', 'des'];

// 如果初始化一个对象， key 为上面数组的的每一项。

function arrToObject(arr, normalValue){
  
  // 正常情况下使用reduce，可能得这样写
  return arr.reduce((r, key)=&gt;{
    r[key] = normalValue;
    return r;
  }, {})
  
  // 但是， 如果使用圆括号
  return arr.reduce((r, key) =&gt; (r[key] = normalValue, r), {});
}





// 再就是更改this指向了
const obj = {
  innerWidth: 2333,
  getInnerWidth(){
    return this.innerWidth;
  }
}

obj.getInnerWidth(); // 2333,
(0, obj.getInnerWidth)(); // 是2333 吗
</code></pre>
<h3 id="18-什么是提升">18. 什么是提升？</h3>
<blockquote>
<p><strong>提升</strong>是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语。</p>
</blockquote>
<p>这里觉得应该是 描述 <strong>变量声明</strong> 和 <strong>函数声明</strong>， 移动到当前作用域顶部的术语。</p>
<p>在预解析阶段， 会把带 <code>var</code> 或 <code>function</code> 关键字的声明提升到该作用域的顶部。</p>
<p>而在执行阶段， 就只是将变量进行赋值。</p>
<p>如下例子:</p>
<pre><code class="language-javascript">function fn(){};
var fn = 1;

var cb = 2;
function cb(){};



// =&gt; 变量提升
function fn(){}; 
var fn; 
var cb;
function cb(){};

// =&gt; 开始执行
// 此处的 function fn(){} 的声明因为提升到预解析的时候声明了， 所以此处跳过函数的fn的声明, 直接到fn 的赋值。
fn = 1;

// 直接  cb 的赋值。
cb = 2;

</code></pre>
<p>注意： 预解析中的变量提升， 只是针对 var 和 function 关键字的声明。</p>
<p>如果是使用let  或者 const的话</p>
<pre><code class="language-javascript">console.log(num); // num is not defined

const num = 123;

{
	console.log(num); // Cannot access 'num' before initialization
  const num = 124;
}

// 从上可以看出， const 不支持预解释， 变量的使用必须在声明的后面。而在私有作用域中， 提前使用未声明的变量时， 则会报出和在全局不一样的错误。 

</code></pre>
<p>此处具体可看 暂存死区</p>
<h3 id="19-什么是作用域">19. 什么是作用域？</h3>
<p>JavaScript 中的作用域是我们可以有效访问变量或函数的区域。JS 有三种类型的作用域：<strong>全局作用域</strong>、<strong>函数作用域</strong>和<strong>块作用域(ES6)</strong>。</p>
<ul>
<li>全局作用域， 在全局作用域中声明的变量或者函数存在于全局作用域中， 在任何作用域中都能访问到它们。</li>
<li>函数作用域， 函数在声明的时候， 会将当前作用域的作用域链存储在自己的 [[Scopes]] 属性中， 而在函数执行的时候， 会产生一个新的私有作用域， 然后再取出自己 [[Scopes]] 中存储的作用域链， 将新的作用域推入该作用域链的最前端， 产出一个新的作用域链。</li>
<li>块级作用域， 在 <code>{}</code> 中通过 let 或 const 声明的变量，只能在其中访问。</li>
</ul>
<p>通过上面对作用域，作用域链的描述。我们可以理解下， 在一个函数作用域中， 查找一个变量的过程。</p>
<pre><code class="language-javascript">var a = 1;
function fn(){
  var b = 2;
  
  function cb (){
    var c = 3;
    console.log(b)
  };
  
  cb();
}

fn();

// =&gt; 代码依次往下， 在全局作用域声明了一个 a， 存值为1；
// =&gt; 然后声明了一个函数fn， 然后将全局的作用域， 塞入了自己的 [[Scopes]] , 此时作用域链为： [{a: 1, ...window}]
// =&gt; 执行fn(), 创建私有作用域，然后拿出fn自己的 [[Scopes]] 属性中的作用域链， 将新产生的私有作用域置入作用域链的最前端， 产出新的作用域链。 并执行fn 中的声明执行完毕， 此时的作用域链中有 [{ b: 2 }, {a: 1, ...window}]。
// =&gt; 然后声明了一个函数 cb， 将当前的作用域链， 作为自己的 [[Scopes]]， 此时的作用域链为： [{ b: 2 }, {a: 1, ...window}]。
// =&gt; 执行 cb()， 创建私有作用域， 然后拿出 cb 自己的 [[Scopes]] 属性中的作用域链， 将新产生的私有作用域置入作用域链的最前端， 产出新的作用域链。此时的作用域链大致为 [{c: 3}, {b: 2}, {a: 1, ...window}]。 然后在 cb 中读取 b 的值， 优先在 [[Scopes]][0] 中查找， 未找到， 然后在 [[Scopes]][1] 中查找... 依次往后，直到 window 为止。

</code></pre>
<p>综上， 一个变量的查找规则就是如此。</p>
<p>现在自身作用域查找， 未找到就上层作用域查找，直到window 为止， 找到则返回值， 没找到则报未定义。</p>
<p>所以， 对此问题， 以前有些性能优化书上有建议， 多次用到的外层作用域变量， 尽量在当前作用域缓存下来以减少变量的查找。</p>
<blockquote>
<p>这块具体可以看看高程第四章的 作用域， 作用域链，变量对象和活动对象</p>
</blockquote>
<p>（对象属性和方法的查找规则也一样，只不过是根据原型和原型链来的）</p>
<h2 id="20-什么是闭包">20. 什么是闭包？</h2>
<p>个人理解：</p>
<p>函数在执行的过程中， 产生了私有作用域， 该私有作用域保护内部的变量不受外界干扰。并同时在<strong>内部创建的复杂数据类型被外界所引用</strong>（不管是return 出去被引用， 还是副作用形式的被外界引用）， 都会导致该函数执行完毕后无法回收内部的变量对象， 无法销毁该作用域， 形成了一个临时性的存储单元。</p>
<p>如：</p>
<pre><code class="language-javascript">
function fn(){
  return [];
}

const v = fn(); // 此时 fn 执行一次产生的作用域就无法被销毁。 这是通过返回值的形式。

// -------------

let v;
function fn(){
  v = [];
}
fn(); // 此时 fn 执行一次产生的作用域就无法被销毁。 这是通过加入副作用， 直接内部创建并赋值给外界变量。


// ------------

let v;
let arr = []
function fn(){
  v = arr;
}

fn(); // 猜一下， 这样是否会形成闭包？

// ------------

let arr = []
function fn(){
  return arr;
}

const v = fn(); // 还有这个呢
</code></pre>
<p>对于上面这几题能理解的话， 基本也就能理解 作用域链，变量对象了，垃圾回收了。 以及在函数内部声明的变量， 都去哪了。还有 arguments 从哪来。</p>
<h3 id="21-javascript-中的虚值是什么">21. JavaScript 中的虚值是什么？</h3>
<blockquote>
<p>const falsyValues = ['', 0, null, undefined, NaN, false];</p>
<p>简单的来说虚值就是是在转换为布尔值时变为 <code>false</code> 的值。</p>
</blockquote>
<h3 id="22-如何检查值是否虚值">22. 如何检查值是否虚值？</h3>
<blockquote>
<p>使用 <code>Boolean</code> 函数或者 <code>!!</code> 运算符。</p>
</blockquote>
<p>个人感觉还是喜欢使用 <code>Boolean</code></p>
<h3 id="23-use-strict-是干嘛用的">23. 'use strict' 是干嘛用的？</h3>
<p>太长直接看原文：</p>
<p><a href="https://juejin.cn/post/6913534577684414472#heading-22">'use strict' 是干嘛用的？</a></p>
<h3 id="24-javascript-中-this-值是什么">24. JavaScript 中 <code>this</code> 值是什么？</h3>
<p><code>this</code> 值的确定，通常要看其使用场景。（以下所讲的函数， 都由 function 创建的普通函数， 而非箭头函数）</p>
<p>在全局作用域中， 非严格模式下， <code>this</code> 指向的 <code>window</code>。严格模式下 <code>this</code> 指向的 <code>undefined</code>。</p>
<p>在函数作用域中， 此时， 又分了几种使用场景（非严格模式）。</p>
<ol>
<li>函数直接调用， 如 <code>fn()</code> ， 此时 <code>fn</code> 中的 <code>this</code> 指向全局。</li>
<li>作为某个对象的方法使用， 如 <code>o.fn()</code> ， 此时， <code>fn</code> 中的 <code>this</code> 指向 <code>o</code></li>
<li>作为构造函数使用， 如 <code>new fn()</code> ， 此时 <code>fn</code> 中的 <code>this</code> 指向新创造出来的实例。</li>
<li>作为 立即执行函数 使用， 如 <code>(function(){})()</code> ， 里面的 <code>this</code> 指向了全局</li>
<li>通过call 或者 apply 来调用， 如果传入的是非 <code>null</code> 和 <code>undefined</code> 的基本数据类型， <code>this</code> 则会指向其对应的包装类型， 否则， this 就会指向 <code>window</code></li>
</ol>
<p>注意： 当为严格模式下， 非严格模式下 <code>this</code> 指向全局的情况， 将会变成 <code>this</code> 指向 <code>undefined</code></p>
<h3 id="25-对象的-prototype原型-是什么">25. 对象的 prototype(原型) 是什么？</h3>
<p>实例取得公有属性或者方法的地方， 是实现继承的核心之一（另外一个就是通过实例的 <strong>__proto__</strong> 之间的关联）</p>
<h3 id="26-什么是-iife它的用途是什么">26. 什么是 IIFE，它的用途是什么？</h3>
<p>自调用函数</p>
<p>分割作用域， 缓存数据，避免全局变量污染。</p>
<h3 id="27-functionprototypeapply-方法的用途是什么">27. Function.prototype.apply 方法的用途是什么？</h3>
<p>调用时，更改调用函数内部this指向， 并接受一个参数数组。第一个参数为内部 <code>this</code> 的指向， 第二个参数是一个数组， 作为函数执行时候的参数)</p>
<h3 id="28-functionprototypecall-方法的用途是什么">28. <code>Function.prototype.call</code> 方法的用途是什么？</h3>
<p>调用时，更改调用函数内部this指向， 并接受一个参数列表。（第一个参数为内部 <code>this</code> 的指向， 第二第三... 的参数都作为函数执行时候的参数）</p>
<h3 id="29-functionprototypeapply-和-functionprototypecall-之间有什么区别">29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别？</h3>
<p>apply 接受的是一个参数数组， call 接受的是一个参数列表。</p>
<p>也就是 apply 的形参个数为2， call 形参个数 可以为更多。</p>
<h3 id="30-functionprototypebind-的用途是什么">30. Function.prototype.bind 的用途是什么？</h3>
<p>更改<code>this</code> 指向， 但不调用， 返回一个新的函数。</p>
<p>第一个参数为 <code>this</code> 的指向， 第2，3... 的则是作为原函数的参数。</p>
<h3 id="31-什么是函数式编程-javascript-的哪些特性使其成为函数式语言的候选语言">31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言</h3>
<p><a href="https://juejin.cn/post/6913534577684414472#heading-30">原文</a></p>
<h3 id="32-什么是高阶函数">32. 什么是高阶函数？</h3>
<blockquote>
<p><strong>高阶函数只是将函数作为参数或返回值的函数。</strong></p>
</blockquote>
<pre><code class="language-javascript">function higherOrderFunction(param,callback){   return callback(param); }
</code></pre>
<h3 id="33-为什么函数被称为一等公民">33. 为什么函数被称为一等公民？</h3>
<blockquote>
<p>在JavaScript中，函数不仅拥有一切传统函数的使用方式（声明和调用），而且可以做到像简单值一样赋值<code>（var func = function(){}）</code>、传参<code>(function func(x,callback){callback();})</code>、返回<code>(function(){return function(){}})</code>，这样的函数也称之为<strong>第一级函数（First-class Function）</strong>。不仅如此，JavaScript中的函数还充当了类的构造函数的作用，同时又是一个<code>Function</code>类的实例(instance)。这样的多重身份让JavaScript的函数变得非常重要。</p>
</blockquote>
<h3 id="34-手动实现-arrayprototypemap-方法">34. 手动实现 <code>Array.prototype.map</code> 方法</h3>
<pre><code class="language-javascript">function map(arr, cb){
  if(arr instanceof Array &amp;&amp; typeof cb === 'function'){
    var resArr = [];
    for(var i = 0; i &lt; arr.length; i++){
			resArr.push(cb(arr[i], i, arr));
    }
    return resArr;
  }
  return [];
}
</code></pre>
<h3 id="35-手动实现arrayprototypefilter方法">35. 手动实现<code>Array.prototype.filter</code>方法</h3>
<pre><code class="language-javascript">function filter(arr, cb){
  if(arr instanceof Array &amp;&amp; typeof cb === 'function'){
    var resArr = [];
    for(var i = 0; i &lt; arr.length; i++){
      const res = cb(arr[i], i, arr);
			res &amp;&amp; resArr.push(res);
    }
    return resArr;
  }
  return [];
}
</code></pre>
<h3 id="36-手动实现arrayprototypereduce方法">36. 手动实现<code>Array.prototype.reduce</code>方法</h3>
<pre><code class="language-javascript">function filter(arr, cb, initialValue){
  if(arr instanceof Array &amp;&amp; typeof cb === 'function'){
    var innerArr = arr.concat([]);
    var resArr = [];
    let value = initialValue === undefined ? innerArr.shift() : initialValue;
    for(var i = 0; i &lt; innerArr.length; i++){
      value = cb(value, innerArr[i], i, arr);
    }
    return value;
  }
  return [];
}
</code></pre>
<h3 id="37-arguments-的对象是什么">37. arguments 的对象是什么？</h3>
<p>普通函数的形参集合， 是一个类数组。</p>
<p>注： 箭头函数没有 <code>arguments</code></p>
<h3 id="38-如何创建一个没有-prototype原型的对象">38. 如何创建一个没有 prototype(原型)的对象？</h3>
<pre><code class="language-javascript">Object.create(null);
</code></pre>
<h3 id="39-为什么在调用这个函数时代码中的b会变成一个全局变量">39. 为什么在调用这个函数时，代码中的<code>b</code>会变成一个全局变量?</h3>
<pre><code class="language-javascript">function myFunc() {  
  let a = b = 0;  
}  
 
myFunc();
</code></pre>
<p><a href="https://juejin.cn/post/6913534577684414472#heading-38">原文</a></p>
<h3 id="40-ecmascript-是什么">40. ECMAScript 是什么？</h3>
<p>语言标准， 浏览器厂商和nodejs 开发者需要按照此标准来设计和开发。目的是为了统一和规范。</p>
<h3 id="41-es6或ecmascript-2015有哪些新特性">41. ES6或ECMAScript 2015有哪些新特性？</h3>
<blockquote>
<ul>
<li>箭头函数</li>
<li>类</li>
<li>模板字符串</li>
<li>加强的对象字面量</li>
<li>对象解构</li>
<li>Promise</li>
<li>生成器</li>
<li>模块</li>
<li>Symbol</li>
<li>代理</li>
<li>Set</li>
<li>函数默认参数</li>
<li>rest 和展开</li>
<li>块作用域</li>
</ul>
</blockquote>
<h3 id="42-varlet和const的区别是什么">42. <code>var</code>,<code>let</code>和<code>const</code>的区别是什么？</h3>
<p>var 在预解释时会进行变量提升， let， const 不会。</p>
<p>var 在全局声明的时候， 会将变量挂载到window上， 而 let 和 const 则是在全局作用域下再开一个作用域， 并位于其中。</p>
<p>var 可以进行重复声明， let，const 不行</p>
<p>let，const 声明的时候会产生块级作用域， var不会。</p>
<h3 id="43-什么是箭头函数">43. 什么是箭头函数？</h3>
<p>语法比普通函数更加简洁， 但是它没有 this， arguments, super，以及不能作为构造函数。</p>
<p>适合用在需要匿名函数的地方。</p>
<h3 id="44-什么是类">44. 什么是类？</h3>
<p>是js 中编写构造函数的新方法。是一个语法糖， 更直观简便的去书写构造函数。最终编译的结果也是构造函数， 继承也是通过构造函数的 <code>prototype</code> 和实例 的 <code>__proto__</code></p>
<h3 id="45-什么是模板字符串">45. 什么是模板字符串？</h3>
<p>两个反单引号包起来的则为末班字符串， 支持回车换行，以及 <code>${}</code> 形式的表达式，使用比以前的 单引号 和 双引号字符串简洁。</p>
<h3 id="46-什么是对象解构">46. 什么是对象解构？</h3>
<blockquote>
<p><strong>对象解构</strong>是从对象或数组中获取或提取值的一种新的、更简洁的方法。</p>
</blockquote>
<h3 id="47-什么是-es6-模块">47. 什么是 ES6 模块？</h3>
<blockquote>
<p><strong>模块</strong>使我们能够将代码基础分割成多个文件，以获得更高的可维护性，并且避免将所有代码放在一个大文件中。</p>
</blockquote>
<p>而es6 模块则是 在es6 版本中提出的 模块概念， 使用 <code>import</code> 来对其他模块功能和值的导入， 使用 <code>export</code> 来对该模块的功能和值的导出。</p>
<p>对应的有 <code>nodejs</code>  端的 <code>commonjs</code> ， 使用的同步模块加载规范， 因为后端的代码都是放在后端服务器， 在执行的时候相当于只是在本地读取文件。</p>
<p>以及 前端的 amd， 异步模块加载规范。因为前端的页面， 图片等资源都是存放在服务器端， 当一个  js 文件需要依赖另一个js文件的时候， 则需要去异步的请求该js文件，因此前端的模块规范是用的 AMD 规范。</p>
<h3 id="48-什么是set对象它是如何工作的">48. 什么是<code>Set</code>对象，它是如何工作的？</h3>
<p><strong>Set</strong> 类似于数组，但是成员的值都是唯一的，没有重复的值。</p>
<p><code>add</code> 方法添加新值， 如果 新值已存在， 则不会添加。</p>
<p><code>delete</code> 删除值， 删除成功返回true， 失败返回false（该值不存在）</p>
<p><code>has</code> 判断是否有该值。</p>
<p><code>clear</code> 清空set</p>
<p><code>size</code>  该 set 的长度</p>
<h3 id="49-什么是回调函数">49. 什么是回调函数？</h3>
<blockquote>
<p><strong>回调函数</strong>是一段可执行的代码段，它作为一个参数传递给其他的代码，其作用是在需要的时候方便调用这段（回调函数）代码。</p>
</blockquote>
<h3 id="50-promise-是什么">50. Promise 是什么？</h3>
<p>异步编程的一种解决方案。分三种状态， 分别为 <code>pendding</code>（等待态）、<code>fulfiled</code>（成功）、<code>rejected</code>（失败）。状态一旦改变， 就不会再变， 初始为 <code>pendding</code>。</p>
<p>其中 ， <code>then</code> 方法接收的回调函数将会在 成功的时候触发。 <code>catch</code> 方法接收的回调函数将会在失败的时候触发。<code>finally</code> 方法接收的回调函数则是不管成功还是失败， 最后都会触发。</p>
<p>以及此方案可以解决 传统回调不断嵌套 的问题。</p>
<pre><code class="language-javascript">// 传统
readFile('path', (data) =&gt; {
  readFile('path', (data) =&gt; {
    readFile('path', (data) =&gt; {
      readFile('path', (data) =&gt; {
    		// ...
      })
    })
  })
})

// 改用promise
readFile('path').then((data) =&gt; {
  return readFile('path')
}).then((data) =&gt; {
  return readFile('path')
}).then((data) =&gt; {
  return readFile('path')
})
</code></pre>
<h3 id="51-什么是-asyncawait-及其如何工作">51. 什么是 <code>async/await</code> 及其如何工作？</h3>
<blockquote>
<p><code>async/await</code>是 JS 中编写异步或非阻塞代码的新方法。它建立在<strong>Promises</strong>之上，让异步代码的可读性和简洁度都更高。</p>
</blockquote>
<p>异常情况下， 使用 try catch 捕获异常。</p>
<pre><code class="language-javascript">try {
  await fn();
}catch(err){
  // err
}
</code></pre>
<h3 id="52-展开spread-运算符和-剩余rest-运算符有什么区别">52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别？</h3>
<p>展开（将一个集合的数据进行展开，就像是一捆火柴， 解开了扎带， 把它们摊开 ）</p>
<pre><code class="language-javascript">const arr = [1,2,3,4,5];

Math.max(...arr); // =&gt; Math.max(1,2,3,4,5)
</code></pre>
<p>将一个对象或者数组进行拆散。</p>
<p>剩余（将一些散开的数据进行整合成一个集合， 就像是一把摊开了的火柴， 用扎带把它们捆成捆）：</p>
<pre><code class="language-javascript">
const {name, age, ...otherInfo} = getUserInfo();

// 此时 otherInfo 就是 除了 name , age 的其他用户信息。

const fn = (...args) =&gt; {
 	// arg 就是fn 执行的时候， 传进来所有实参的集合， 是个数组
}

</code></pre>
<h3 id="53-什么是默认参数">53. 什么是默认参数？</h3>
<blockquote>
<p>默认参数是在 JS 中定义默认变量的一种新方法，它在ES6或ECMAScript 2015版本中可用。</p>
</blockquote>
<pre><code class="language-javascript">// ES6：
function fn(a = 0, b = 0){
}

// ES5:
function fn(a, b){
  a = a || 0;
  b = b || 0;
}


// 此处要注意的是， 因为 es5 使用的是短路运算符 || 去进行取默认值的，  所以当a 为 假值时， 都会取到默认值 0， 比如为 false, undefined, null, '' 之类的。
// 而在 es6中，  只有 a 为undefined 的时候， 才会去取默认值0， 而当a 为null， false, 的时候， 就不会去取默认值了。
</code></pre>
<h3 id="54-什么是包装对象wrapper-object">54. 什么是包装对象（wrapper object）？</h3>
<p>基本数据类型是没有属性和方法的（除 <code>undefined</code> 和 <code>null</code>）， 但是在实际使用的时候， 却可以是用属性和方法。如：</p>
<pre><code class="language-javascript">str.split();
str.length;
</code></pre>
<p>而此时， 就涉及到题目的 <strong>包装对象</strong> 了。</p>
<p>而上面的两行代码， 都可以看成是：</p>
<pre><code class="language-javascript">(new String(str)).split();
(new String(str)).length
</code></pre>
<p>当执行完毕后， 对应的实例也就会被销毁。</p>
<p>最后可以根据上面的来尝试下这个例子，进行辅助理解下。</p>
<pre><code class="language-javascript">const str = 'c';
str.githubName = 'ccc';
console.log(str.githubName); // ???
</code></pre>
<h3 id="55-隐式和显式转换有什么区别">55. 隐式和显式转换有什么区别？</h3>
<blockquote>
<p>隐式强制转换是一种将值转换为另一种类型的方法，这个过程是自动完成的，无需我们手动操作。</p>
</blockquote>
<p>如：</p>
<pre><code class="language-javascript">// 将一个字符串转为数字
string - 0;

// 将一个数字转为字符串
number + '';
</code></pre>
<p><strong>将运算符左右两边的不同数据类型， 先进行转换成同一数据类型， 然后再进行运算</strong></p>
<blockquote>
<p>而显式强制是将值转换为另一种类型的方法，我们需要手动转换。</p>
</blockquote>
<pre><code class="language-javascript">// 将一个字符串转为数字
Number(string);

// 将一个数字转为字符串
String(number);
</code></pre>
<p><strong>开发者直接使用转换数据类型的函数来对数据进行类型的转换</strong></p>
<h3 id="56-什么是nan以及如何检查值是否为nan">56. 什么是NaN？以及如何检查值是否为NaN？</h3>
<p><code>NaN</code> 是<code>Not a Number</code>的首字母，表示是一个非数字的 数字类型值。</p>
<p>因为  NaN !== NaN， 所以可以使用  <code>isNaN</code> 函数进行检测值是否为NaN。 (尽量使用 <code>Number.isNaN</code> ， 而非全局的 <code>isNaN</code>)</p>
<h3 id="57-如何判断值是否为数组">57. 如何判断值是否为数组？</h3>
<ol>
<li>
<p>使用内置的， <code>Array.isArray</code> 函数进行判断</p>
</li>
<li>
<p>自己封装类型检测函数</p>
<pre><code class="language-javascript">function typeOf(value) {
  return Object.prototype.toString.call(value).slice(8, -1);
}

// 如果返回的是字符串 'Array', 那么就说明该传入的数据是 数组。 以及我们可以基于此函数， 再进行封装一次。

function isArray(value){
  return typeOf(value) === 'Array'
}
</code></pre>
</li>
<li>
<p><code>arr instanceof Array</code></p>
<p>此方式是  <code>实例 instanceof 构造函数（构造器）</code> , 可以根据实例的原型和原型链， 逐步检测 构造器 是否匹配。(重点是 <code>constractor</code> )</p>
</li>
</ol>
<h3 id="58-如何在不使用模运算符的情况下检查一个数字是否是偶数">58. 如何在不使用<code>%</code>模运算符的情况下检查一个数字是否是偶数？</h3>
<p><a href="https://juejin.cn/post/6913534577684414472#heading-57">原文链接</a></p>
<h3 id="59-如何检查对象中是否存在某个属性">59. 如何检查对象中是否存在某个属性？</h3>
<ol>
<li><code>in</code> 操作符。如 <code>'a' in object</code></li>
<li><code>hsaOwnProperty</code>。如<code>object.hasOwnProperty('a')</code></li>
</ol>
<h3 id="60-ajax-是什么">60. AJAX 是什么？</h3>
<p>支持js 和 服务器进行交互的 webapi。</p>
<p>让网页的局部更新成为了可能（传统都是需要重新刷新整个页面）</p>
<h3 id="61-如何在-js-中创建对象">61. 如何在 JS 中创建对象？</h3>
<ol>
<li>字面量  <code>const obj = {name: 'c'}</code></li>
<li>构造函数 <code>function Person (name){ this.name = name}; const obj = new Person('c')</code></li>
<li><code>Object.create</code> ， 如 ： <code>const obj = Object.create({})</code></li>
</ol>
<h3 id="62-objectseal-和-objectfreeze-方法之间有什么区别">62. Object.seal 和 Object.freeze 方法之间有什么区别？</h3>
<p><code>Object.seal</code> 方法生成密封对象， 只支持原有可写属性的继续修改。其他的新增， 删除，配置对象的属性（Object.defineProperties）特性都不被允许。</p>
<p>而 <code>Object.freeze</code> 则是比 <code>Object.seal</code> 更加严格， 使整个对象下面的所有属性都是只读的。</p>
<h3 id="63-in-运算符和-objecthasownproperty-方法有什么区别">63. <code>in</code> 运算符和 <code>Object.hasOwnProperty</code> 方法有什么区别？</h3>
<p><code>hasOwnProperty</code> 是只在对象自身私有属性或方法中进行查找。</p>
<p><code>in</code> 则是会从自身属性开始， 沿着原型链进行查找。</p>
<h3 id="64-有哪些方法可以处理-js-中的异步代码">64. 有哪些方法可以处理 JS 中的异步代码？</h3>
<ol>
<li>回调函数</li>
<li>Promise</li>
<li>generator 函数</li>
<li>async/await</li>
</ol>
<h3 id="65-函数表达式和函数声明之间有什么区别">65. 函数表达式和函数声明之间有什么区别？</h3>
<pre><code class="language-javascript">function fn1(){};

var fn2 = function(){};
</code></pre>
<p>在预解释上， 通过 <code>function</code> 关键字声明的，会在预解释的时候提升到作用域顶部进行预先声明+定义。</p>
<p>而使用 <code>var</code> 关键字声明的， 在预解释阶段只是会把声明提升。后面的赋值还得等到js执行流执行到这个赋值位置才会对该处进行赋值。</p>
<p>而上面的两种情况， 也就导致了在调用的时候， 如果是在声明之前调用， 那 <code>var</code> 关键字的就会报错。</p>

              </div>
              <div class="toc-container">
                <ul class="markdownIt-TOC">
<li><a href="#%E9%9D%A2%E8%AF%95%E9%A2%98%E7%90%86%E8%A7%A3">面试题理解</a>
<ul>
<li><a href="#1undefined-%E5%92%8C-null-%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">1.undefined 和 null 有什么区别？</a></li>
<li><a href="#2-%E8%BF%90%E7%AE%97%E7%AC%A6">2. &amp;&amp; 运算符</a></li>
<li><a href="#3-%E8%BF%90%E7%AE%97%E7%AC%A6%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88">3. || 运算符能做什么</a>
<ul>
<li><a href="#4-%E4%BD%BF%E7%94%A8-%E6%88%96%E4%B8%80%E5%85%83%E5%8A%A0%E8%BF%90%E7%AE%97%E7%AC%A6%E6%98%AF%E5%B0%86%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E4%B8%BA%E6%95%B0%E5%AD%97%E7%9A%84%E6%9C%80%E5%BF%AB%E6%96%B9%E6%B3%95%E5%90%97">4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗？</a></li>
</ul>
</li>
<li><a href="#5-dom-%E6%98%AF%E4%BB%80%E4%B9%88">5. DOM 是什么？</a></li>
<li><a href="#6-%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E4%BC%A0%E6%92%AD">6. 什么是事件传播?</a></li>
<li><a href="#7-%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1">7. 什么是事件冒泡？</a>
<ul>
<li><a href="#8-%E4%BB%80%E4%B9%88%E6%98%AF%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7">8. 什么是事件捕获？</a></li>
<li><a href="#9-eventpreventdefault-%E5%92%8C-eventstoppropagation%E6%96%B9%E6%B3%95%E4%B9%8B%E9%97%B4%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别？</a></li>
<li><a href="#10-%E5%A6%82%E4%BD%95%E7%9F%A5%E9%81%93%E6%98%AF%E5%90%A6%E5%9C%A8%E5%85%83%E7%B4%A0%E4%B8%AD%E4%BD%BF%E7%94%A8%E4%BA%86eventpreventdefault%E6%96%B9%E6%B3%95">10. 如何知道是否在元素中使用了<code>event.preventDefault()</code>方法？</a></li>
<li><a href="#11-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AD%A4%E4%BB%A3%E7%A0%81-objsomepropx-%E4%BC%9A%E5%BC%95%E5%8F%91%E9%94%99%E8%AF%AF">11. 为什么此代码 <code>obj.someprop.x</code> 会引发错误?</a></li>
</ul>
</li>
<li><a href="#12-%E4%BB%80%E4%B9%88%E6%98%AF-eventtarget">12. 什么是 event.target ？</a></li>
<li><a href="#13-%E4%BB%80%E4%B9%88%E6%98%AF-eventcurrenttarget">13. 什么是 event.currentTarget？？</a>
<ul>
<li><a href="#14-%E5%92%8C-%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">14. == 和 === 有什么区别？</a></li>
<li><a href="#15-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%9C%A8-js-%E4%B8%AD%E6%AF%94%E8%BE%83%E4%B8%A4%E4%B8%AA%E7%9B%B8%E4%BC%BC%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%97%B6%E8%BF%94%E5%9B%9E-false">15. 为什么在 JS 中比较两个相似的对象时返回 false？</a></li>
<li><a href="#16-%E8%BF%90%E7%AE%97%E7%AC%A6%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88">16. !! 运算符能做什么？</a></li>
<li><a href="#17-%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%80%E8%A1%8C%E4%B8%AD%E8%AE%A1%E7%AE%97%E5%A4%9A%E4%B8%AA%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%80%BC">17. 如何在一行中计算多个表达式的值？</a></li>
<li><a href="#18-%E4%BB%80%E4%B9%88%E6%98%AF%E6%8F%90%E5%8D%87">18. 什么是提升？</a></li>
<li><a href="#19-%E4%BB%80%E4%B9%88%E6%98%AF%E4%BD%9C%E7%94%A8%E5%9F%9F">19. 什么是作用域？</a></li>
</ul>
</li>
<li><a href="#20-%E4%BB%80%E4%B9%88%E6%98%AF%E9%97%AD%E5%8C%85">20. 什么是闭包？</a>
<ul>
<li><a href="#21-javascript-%E4%B8%AD%E7%9A%84%E8%99%9A%E5%80%BC%E6%98%AF%E4%BB%80%E4%B9%88">21. JavaScript 中的虚值是什么？</a></li>
<li><a href="#22-%E5%A6%82%E4%BD%95%E6%A3%80%E6%9F%A5%E5%80%BC%E6%98%AF%E5%90%A6%E8%99%9A%E5%80%BC">22. 如何检查值是否虚值？</a></li>
<li><a href="#23-use-strict-%E6%98%AF%E5%B9%B2%E5%98%9B%E7%94%A8%E7%9A%84">23. 'use strict' 是干嘛用的？</a></li>
<li><a href="#24-javascript-%E4%B8%AD-this-%E5%80%BC%E6%98%AF%E4%BB%80%E4%B9%88">24. JavaScript 中 <code>this</code> 值是什么？</a></li>
<li><a href="#25-%E5%AF%B9%E8%B1%A1%E7%9A%84-prototype%E5%8E%9F%E5%9E%8B-%E6%98%AF%E4%BB%80%E4%B9%88">25. 对象的 prototype(原型) 是什么？</a></li>
<li><a href="#26-%E4%BB%80%E4%B9%88%E6%98%AF-iife%E5%AE%83%E7%9A%84%E7%94%A8%E9%80%94%E6%98%AF%E4%BB%80%E4%B9%88">26. 什么是 IIFE，它的用途是什么？</a></li>
<li><a href="#27-functionprototypeapply-%E6%96%B9%E6%B3%95%E7%9A%84%E7%94%A8%E9%80%94%E6%98%AF%E4%BB%80%E4%B9%88">27. Function.prototype.apply 方法的用途是什么？</a></li>
<li><a href="#28-functionprototypecall-%E6%96%B9%E6%B3%95%E7%9A%84%E7%94%A8%E9%80%94%E6%98%AF%E4%BB%80%E4%B9%88">28. <code>Function.prototype.call</code> 方法的用途是什么？</a></li>
<li><a href="#29-functionprototypeapply-%E5%92%8C-functionprototypecall-%E4%B9%8B%E9%97%B4%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">29. Function.prototype.apply 和 Function.prototype.call 之间有什么区别？</a></li>
<li><a href="#30-functionprototypebind-%E7%9A%84%E7%94%A8%E9%80%94%E6%98%AF%E4%BB%80%E4%B9%88">30. Function.prototype.bind 的用途是什么？</a></li>
<li><a href="#31-%E4%BB%80%E4%B9%88%E6%98%AF%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B-javascript-%E7%9A%84%E5%93%AA%E4%BA%9B%E7%89%B9%E6%80%A7%E4%BD%BF%E5%85%B6%E6%88%90%E4%B8%BA%E5%87%BD%E6%95%B0%E5%BC%8F%E8%AF%AD%E8%A8%80%E7%9A%84%E5%80%99%E9%80%89%E8%AF%AD%E8%A8%80">31. 什么是函数式编程? JavaScript 的哪些特性使其成为函数式语言的候选语言</a></li>
<li><a href="#32-%E4%BB%80%E4%B9%88%E6%98%AF%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0">32. 什么是高阶函数？</a></li>
<li><a href="#33-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%87%BD%E6%95%B0%E8%A2%AB%E7%A7%B0%E4%B8%BA%E4%B8%80%E7%AD%89%E5%85%AC%E6%B0%91">33. 为什么函数被称为一等公民？</a></li>
<li><a href="#34-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0-arrayprototypemap-%E6%96%B9%E6%B3%95">34. 手动实现 <code>Array.prototype.map</code> 方法</a></li>
<li><a href="#35-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0arrayprototypefilter%E6%96%B9%E6%B3%95">35. 手动实现<code>Array.prototype.filter</code>方法</a></li>
<li><a href="#36-%E6%89%8B%E5%8A%A8%E5%AE%9E%E7%8E%B0arrayprototypereduce%E6%96%B9%E6%B3%95">36. 手动实现<code>Array.prototype.reduce</code>方法</a></li>
<li><a href="#37-arguments-%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E4%BB%80%E4%B9%88">37. arguments 的对象是什么？</a></li>
<li><a href="#38-%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%B2%A1%E6%9C%89-prototype%E5%8E%9F%E5%9E%8B%E7%9A%84%E5%AF%B9%E8%B1%A1">38. 如何创建一个没有 prototype(原型)的对象？</a></li>
<li><a href="#39-%E4%B8%BA%E4%BB%80%E4%B9%88%E5%9C%A8%E8%B0%83%E7%94%A8%E8%BF%99%E4%B8%AA%E5%87%BD%E6%95%B0%E6%97%B6%E4%BB%A3%E7%A0%81%E4%B8%AD%E7%9A%84b%E4%BC%9A%E5%8F%98%E6%88%90%E4%B8%80%E4%B8%AA%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F">39. 为什么在调用这个函数时，代码中的<code>b</code>会变成一个全局变量?</a></li>
<li><a href="#40-ecmascript-%E6%98%AF%E4%BB%80%E4%B9%88">40. ECMAScript 是什么？</a></li>
<li><a href="#41-es6%E6%88%96ecmascript-2015%E6%9C%89%E5%93%AA%E4%BA%9B%E6%96%B0%E7%89%B9%E6%80%A7">41. ES6或ECMAScript 2015有哪些新特性？</a></li>
<li><a href="#42-varlet%E5%92%8Cconst%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88">42. <code>var</code>,<code>let</code>和<code>const</code>的区别是什么？</a></li>
<li><a href="#43-%E4%BB%80%E4%B9%88%E6%98%AF%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0">43. 什么是箭头函数？</a></li>
<li><a href="#44-%E4%BB%80%E4%B9%88%E6%98%AF%E7%B1%BB">44. 什么是类？</a></li>
<li><a href="#45-%E4%BB%80%E4%B9%88%E6%98%AF%E6%A8%A1%E6%9D%BF%E5%AD%97%E7%AC%A6%E4%B8%B2">45. 什么是模板字符串？</a></li>
<li><a href="#46-%E4%BB%80%E4%B9%88%E6%98%AF%E5%AF%B9%E8%B1%A1%E8%A7%A3%E6%9E%84">46. 什么是对象解构？</a></li>
<li><a href="#47-%E4%BB%80%E4%B9%88%E6%98%AF-es6-%E6%A8%A1%E5%9D%97">47. 什么是 ES6 模块？</a></li>
<li><a href="#48-%E4%BB%80%E4%B9%88%E6%98%AFset%E5%AF%B9%E8%B1%A1%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84">48. 什么是<code>Set</code>对象，它是如何工作的？</a></li>
<li><a href="#49-%E4%BB%80%E4%B9%88%E6%98%AF%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0">49. 什么是回调函数？</a></li>
<li><a href="#50-promise-%E6%98%AF%E4%BB%80%E4%B9%88">50. Promise 是什么？</a></li>
<li><a href="#51-%E4%BB%80%E4%B9%88%E6%98%AF-asyncawait-%E5%8F%8A%E5%85%B6%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C">51. 什么是 <code>async/await</code> 及其如何工作？</a></li>
<li><a href="#52-%E5%B1%95%E5%BC%80spread-%E8%BF%90%E7%AE%97%E7%AC%A6%E5%92%8C-%E5%89%A9%E4%BD%99rest-%E8%BF%90%E7%AE%97%E7%AC%A6%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别？</a></li>
<li><a href="#53-%E4%BB%80%E4%B9%88%E6%98%AF%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0">53. 什么是默认参数？</a></li>
<li><a href="#54-%E4%BB%80%E4%B9%88%E6%98%AF%E5%8C%85%E8%A3%85%E5%AF%B9%E8%B1%A1wrapper-object">54. 什么是包装对象（wrapper object）？</a></li>
<li><a href="#55-%E9%9A%90%E5%BC%8F%E5%92%8C%E6%98%BE%E5%BC%8F%E8%BD%AC%E6%8D%A2%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">55. 隐式和显式转换有什么区别？</a></li>
<li><a href="#56-%E4%BB%80%E4%B9%88%E6%98%AFnan%E4%BB%A5%E5%8F%8A%E5%A6%82%E4%BD%95%E6%A3%80%E6%9F%A5%E5%80%BC%E6%98%AF%E5%90%A6%E4%B8%BAnan">56. 什么是NaN？以及如何检查值是否为NaN？</a></li>
<li><a href="#57-%E5%A6%82%E4%BD%95%E5%88%A4%E6%96%AD%E5%80%BC%E6%98%AF%E5%90%A6%E4%B8%BA%E6%95%B0%E7%BB%84">57. 如何判断值是否为数组？</a></li>
<li><a href="#58-%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8D%E4%BD%BF%E7%94%A8%E6%A8%A1%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%A3%80%E6%9F%A5%E4%B8%80%E4%B8%AA%E6%95%B0%E5%AD%97%E6%98%AF%E5%90%A6%E6%98%AF%E5%81%B6%E6%95%B0">58. 如何在不使用<code>%</code>模运算符的情况下检查一个数字是否是偶数？</a></li>
<li><a href="#59-%E5%A6%82%E4%BD%95%E6%A3%80%E6%9F%A5%E5%AF%B9%E8%B1%A1%E4%B8%AD%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%AA%E5%B1%9E%E6%80%A7">59. 如何检查对象中是否存在某个属性？</a></li>
<li><a href="#60-ajax-%E6%98%AF%E4%BB%80%E4%B9%88">60. AJAX 是什么？</a></li>
<li><a href="#61-%E5%A6%82%E4%BD%95%E5%9C%A8-js-%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1">61. 如何在 JS 中创建对象？</a></li>
<li><a href="#62-objectseal-%E5%92%8C-objectfreeze-%E6%96%B9%E6%B3%95%E4%B9%8B%E9%97%B4%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">62. Object.seal 和 Object.freeze 方法之间有什么区别？</a></li>
<li><a href="#63-in-%E8%BF%90%E7%AE%97%E7%AC%A6%E5%92%8C-objecthasownproperty-%E6%96%B9%E6%B3%95%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">63. <code>in</code> 运算符和 <code>Object.hasOwnProperty</code> 方法有什么区别？</a></li>
<li><a href="#64-%E6%9C%89%E5%93%AA%E4%BA%9B%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E5%A4%84%E7%90%86-js-%E4%B8%AD%E7%9A%84%E5%BC%82%E6%AD%A5%E4%BB%A3%E7%A0%81">64. 有哪些方法可以处理 JS 中的异步代码？</a></li>
<li><a href="#65-%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%92%8C%E5%87%BD%E6%95%B0%E5%A3%B0%E6%98%8E%E4%B9%8B%E9%97%B4%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB">65. 函数表达式和函数声明之间有什么区别？</a></li>
</ul>
</li>
</ul>
</li>
</ul>

              </div>
            </div>
          </article>
        </div>

        
          <div class="next-post">
            <div class="next">下一篇</div>
            <a href="https://croatiaparanoia.github.io/blog/post/polyfill/">
              <h3 class="post-title">
                Polyfill
              </h3>
            </a>
          </div>
        

        
          
            <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>

<div id="gitalk-container"></div>

<script>

  var gitalk = new Gitalk({
    clientID: '344de4a7a0e3121bcdbc',
    clientSecret: 'cf3ede59043d5bf3f50b37b93791396bb4d1267e',
    repo: 'blog',
    owner: 'CroatiaParanoia',
    admin: ['CroatiaParanoia'],
    id: (location.pathname).substring(0, 49),      // Ensure uniqueness and length less than 50
    distractionFreeMode: false  // Facebook-like distraction free mode
  })

  gitalk.render('gitalk-container')

</script>

          

          
        

        <div class="site-footer">
  Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a>
  <a class="rss" href="https://croatiaparanoia.github.io/blog//atom.xml" target="_blank">
    <i class="ri-rss-line"></i> RSS
  </a>
</div>

      </div>
    </div>

    <script>
      hljs.initHighlightingOnLoad()

      let mainNavLinks = document.querySelectorAll(".markdownIt-TOC a");

      // This should probably be throttled.
      // Especially because it triggers during smooth scrolling.
      // https://lodash.com/docs/4.17.10#throttle
      // You could do like...
      // window.addEventListener("scroll", () => {
      //    _.throttle(doThatStuff, 100);
      // });
      // Only not doing it here to keep this Pen dependency-free.

      window.addEventListener("scroll", event => {
        let fromTop = window.scrollY;

        mainNavLinks.forEach((link, index) => {
          let section = document.getElementById(decodeURI(link.hash).substring(1));
          let nextSection = null
          if (mainNavLinks[index + 1]) {
            nextSection = document.getElementById(decodeURI(mainNavLinks[index + 1].hash).substring(1));
          }
          if (section.offsetTop <= fromTop) {
            if (nextSection) {
              if (nextSection.offsetTop > fromTop) {
                link.classList.add("current");
              } else {
                link.classList.remove("current");    
              }
            } else {
              link.classList.add("current");
            }
          } else {
            link.classList.remove("current");
          }
        });
      });

    </script>
  </body>
</html>
